from game.pathing import PathManager
import xml.etree.ElementTree as etree
import random
from game.level import *


class LevelGenerator:
    def __init__(self, res):
        self.res_mgr = res
        self.path_mgr = PathManager([], ['room'])
        self.tree = etree.parse("data/x_level.xml")

    def generate_level(self, theme, dlevel):
        tree = self.tree

        themes = tree.getiterator('theme')
        theme_node = None
        for tn in themes:
            if tn.get('name') == theme:
                theme_node = tn
                break

        if theme_node is None:
            raise NameError('Theme not found: {0}'.format(theme))

        dlvls = theme_node.getiterator('dlvl')
        dlvl_node = None
        for dn in dlvls:
            if dn.get('lvl') == dlevel:
                dlvl_node = dn

        if dlvl_node is None:
            raise NameError('Dungeon level not found: {0}'.format(dlevel))

        gen_type = dlvl_node.get('gen_type')
        if gen_type == 'bsp':
            return self.generate_bsp(dlvl_node, theme)

    def generate_bsp(self, node, theme):
        #the width of the dungeon in tiles
        minw = int(node.get('min_width'))
        maxw = int(node.get('max_width', minw))
        #the height of the dungeon in tiles
        minh = int(node.get('min_height'))
        maxh = int(node.get('max_height', minh))
        #the number of iterations to split the bsp tree
        mini = int(node.get('min_iter'))
        maxi = int(node.get('max_iter', mini))
        #the ratio of which to make each split
        minr = int(node.get('min_split'))
        maxr = int(node.get('max_split', minr))

        #make a random width and height based on the settings
        width = random.randint(minw, maxw)
        height = random.randint(minh, maxh)
        #random number of iterations
        iter = random.randint(mini, maxi)

        level = Level(width, height, theme, (32,32))
        root = Room(0, 0, width, height)
        level.rooms = root
        self.res_mgr.load_tileset(level)

        self.bsp_recurse(level, root, iter, minr, maxr)

        return level


    def bsp_recurse(self, level, room, iter, minr, maxr):

        #we are at the last leaf
        if iter == 0 or (room.w < 10 and room.h < 10):
            #need at least 5 tiles each way so that the room is at least 1 tile
            if room.w < 5 or room.h < 5:
                #make the parent leaf not split
                raise NameError('Room too small: {0}, {1}'.format(room.w, room.h))
            #make the actual room
            #get a random coord from the top-left quadrant
            x1, y1 = room.random_x(0.0, 30.0), room.random_y(0.0, 30.0)
            x2, y2 = room.random_x(70.0, 100.0), room.random_y(70.0, 100.0)

            if x2 - x1 < 3:
                x1, x2 = room.x + 1, room.xw - 1

            if y2 -y1 < 3:
                y1, y2 = room.y + 1, room.yh - 1
                
#            print "Making room. Original {0},{1} to {2},{3}, New {4},{5} to {6},{7}".format(room.x, room.y, room.xw, room.yh, x1,y1,x2,y2)
            room.x, room.y = x1, y1
            room.w, room.h = x2 - x1, y2 - y1                
            room.xw, room.yh = x2, y2



            for i in xrange(x1, x2 + 1):
                for j in xrange(y1, y2 + 1):
                    level.tiles[i][j].terrain = self.res_mgr.load_terrain('room')
                    if i == x1 and j == y1:
                        level.tiles[i][j].doodad = self.res_mgr.load_doodad('wall', 'north_west')
                    elif i == x1 and j == y2:
                        level.tiles[i][j].doodad = self.res_mgr.load_doodad('wall', 'south_west')
                    elif i == x2 and j == y2:
                        level.tiles[i][j].doodad = self.res_mgr.load_doodad('wall', 'south_east')
                    elif i == x2 and j == y1:
                        level.tiles[i][j].doodad = self.res_mgr.load_doodad('wall', 'north_east')
                    elif i == x1:
                        level.tiles[i][j].doodad = self.res_mgr.load_doodad('wall', 'west')
                    elif i == x2:
                        level.tiles[i][j].doodad = self.res_mgr.load_doodad('wall', 'east')
                    elif j == y1:
                        level.tiles[i][j].doodad = self.res_mgr.load_doodad('wall', 'north')
                    elif j == y2:
                        level.tiles[i][j].doodad = self.res_mgr.load_doodad('wall', 'south')


        #otherwise, split again
        else:
            #make a horizontal or vertical split?
            if room.w < 10: split_dir = 'h'
            elif room.h < 10: split_dir = 'v'
            else:
                split_dir = 'h'
                r = random.randint(0, 1)
                if r == 0:
                    split_dir = 'v'

            if split_dir == 'h':
                #randomly split
                s = room.random_y(minr, maxr) - room.y
                #make sure it is large enough
                if s < 5: s = 5
                elif room.h - s < 5: s = room.h - 5
                    
                lx, ly, lw, lh = room.x, room.y, room.w, s
                rx, ry, rw, rh = room.x, room.y + s, room.w, room.h - s
                
            else:
                #randomly split
                s = room.random_x(minr, maxr) - room.x
                #make sure it is large enough
                if s < 5: s = 5
                elif room.w - s < 5: s = room.w - 5

                lx, ly, lw, lh = room.x, room.y, s, room.h
                rx, ry, rw, rh = room.x + s, room.y, room.w - s, room.h

            if lw < 0:
                print "not left {0}".format(lw)
            if rw < 0:
                print "not right {0}".format(rw)
            room.left = Room(lx, ly, lw, lh)
            room.right = Room(rx, ry, rw, rh)
                
            self.bsp_recurse(level, room.left, iter-1, minr, maxr)
            self.bsp_recurse(level, room.right, iter-1, minr, maxr)

            conn_room_l = room.left
            conn_room_r = room.right

            while not conn_room_l.leaf():
                r = random.randint(0, 1)
                if r == 1: conn_room_l = conn_room_l.left
                else: conn_room_l = conn_room_l.right

            while not conn_room_r.leaf():
                r = random.randint(0, 1)
                if r == 1: conn_room_r = conn_room_r.left
                else: conn_room_r = conn_room_r.right

            if split_dir == 'h':
                lsx, lsy = conn_room_l.random_x(), conn_room_l.yh
                rsx, rsy = conn_room_r.random_x(), conn_room_r.y
            else:
                lsx, lsy = conn_room_l.xw, conn_room_l.random_y()
                rsx, rsy = conn_room_r.x, conn_room_r.random_y()

            #make corridor from lsx, lsy to rsx, rsy
            path = self.path_mgr.find_path(level, (lsx, lsy), (rsx, rsy), diag=0)
            for c, p in path:
                if c == 0 or c == 'last':
                    level.tiles[p.x][p.y].doodad = self.res_mgr.load_doodad('door', 'open')
                level.tiles[p.x][p.y].terrain = self.res_mgr.load_terrain('corridor')







